<?php
namespace classlib\validator;
use classlib\input;
use classlib\core\lang;
class AuditorException extends \Exception {
	private $field;
	public function __construct($msg, $code, $field) {
		parent::__construct($msg, $code);
		$this->field = $field;
	}
	public function getField() {
		return $this->field;
	}
};

class auditor {
	/**
	 * 要处理的验证的字段信息
	 * @var string
	 */
	private $field;
	
	/**
	 * 定义验证规则的策略
	 * @var array name|args|func[名称]
	 */
	private $rules;
	
	/**
	 * 定义注册的匿名验证函数
	 * @var array $handle
	 */
	private $handles;
	
	/**
	 * 错误信息提示语
	 * @var lang
	 */
	private $lang;
	
	/**
	 * 定义两个日期时间格式
	 * @var string
	 */
	public static $pdate = '/^[\d]{4}\-[\d]{1,2}\-[\d]{1,2}$/';
	public static $ptime = '/^[\d]{2}:[\d]{1,2}:[\d]{1,2}$/';
	
	/**
	 * 构造函数初始化一个验证器类
	 * @return void
	 */
	public function __construct() {
		$this->handles = array();
		$this->rules   = array();
		$this->field   = '';
	}
	
	/**
	 * 调用禁言验证一个字段是否合法 返回true|false
	 * @param string $rule
	 * @param string $args
	 * @throws AuditorException
	 * @return bool
	 */
	public static function __callStatic($rule, $args) {
		static $inst = NULL;
		($inst == NULL) && $inst = new static();
		$rule  = substr($rule, 2);
		if (!method_exists($inst, $rule) || count($args) != 1) {
			$field = (count($args) > 0)? $args[0]:'undefined';
			throw new AuditorException('verify call function:'.$rule.' not exists.', 500, $field);
		}
		$res = $inst->reset($args[0])->$rule()->call_rule();
		return $res;
	}
	
	/**
	 * 对请求的参数id列表做简单的过滤判断处理
	 * @param string $field
	 * @return array|bool
	 */
	public static function intstr2arr($field) {
		$idstr = input::get_post($field);
		if (!$idstr) {
			return false;
		}
		$idstr = explode(',', $idstr);
		$idstr = array_filter($idstr, 'is_numeric');
		$idstr = array_unique($idstr);
		return $idstr;
	}
	
	/**
	 * 设置语言包
	 * @param lang $lang
	 * @return auditor
	 */
	public function lang($lang) {
		$this->lang = $lang;
		return $this;
	}
	
	/**
	 * 清理重置验证器
	 * @param string $field
	 * @return \classlib\validator\auditor
	 */
	public function reset($field) {
		$this->rules = array();
		$this->field = $field;
		return $this;
	}
	
	/**
	 * 添加一条规则到记录当中
	 * @param string $rule
	 * @param callback $func
	 * @param string $name
	 * @param mix    $args
	 * @throws ValidatorException
	 */
	protected function add_rule($rule, $func, $args) {
		if (!is_callable($func)) {
			throw new AuditorException('verify call function:'.$rule.' not exists.', 500, $this->field);
		}
		(!isset($this->handles[$rule])) && $this->handles[$rule] = $func;
		$this->rules[] = array($rule, $args);
	}
	
	/**
	 * 调用最后一条规则资料信息
	 * @return bool 返回验证结果
	 */
	public function call_rule() {
		$data = input::get_post($this->field);
		$rule = array_pop($this->rules);
		if (empty($rule)) {
			return false;
		}
		return $this->handles[$rule[0]]($data, $rule[1]);
	}
	
	/**
	 * 执行验证队列产生的结果
	 * @return mixed $data
	 */
	public function run() {
		$data = input::get_post($this->field);
		foreach ($this->rules as &$rule) {
			$res = $this->handles[$rule[0]]($data, $rule[1]);
			if (!$res) {//验证返回错误的时候
				$msg = $this->lang->txt('auditor', $rule[0]);
				(!$msg) && $msg = $this->lang->txt('auditor', 'default');
				switch ($rule[0]) {
					case 'in':
						$msg = sprintf($msg, $this->field, implode(',', $rule[1]));
						break;
					case 'min':
					case 'max':
					case 'minlen':
					case 'maxlen':
						$msg = sprintf($msg, $this->field, $rule[1]);
						break;
					case 'between':
					case 'lbetween':
						$msg = sprintf($msg, $this->field, $rule[1][0], $rule[1][1]);
						break;
					default:
						$msg = sprintf($msg, $this->field);
				}
				list($code, $msg) = explode('~', $msg);
				throw new AuditorException($msg, $code, $this->field);
			}
		}
		return $data;
	}
	
	/**
	 * 验证一个必传字段是否存在
	 * @return \classlib\validator\auditor
	 */
	public function required() {
		$this->add_rule(__FUNCTION__, function($data, $args=null) {
			return ($data === null)? false:true;
		}, null);
		return $this;
	}
	
	/**
	 * 验证一个字符串不含空格字母等
	 * @return \classlib\validator\auditor
	 */
	public function nospace() {
		$this->add_rule(__FUNCTION__, function($data, $args) {
			return preg_match($args, $data)? false:true;
		}, '/\s/');
		return $this;
	}
	
	/**
	 * 判断一个参数值是否在指定的数组中
	 * @param array $in
	 * @return \classlib\validator\auditor
	 */
	public function in($in = array()) {
		$this->add_rule(__FUNCTION__, function($data, $args) {
			return in_array($data, $args);
		}, $in);
		return $this;
	}
	
	/**
	 * 验证一个字符串是IP地址
	 * @return \classlib\validator\auditor
	 */
	public function ip() {
		$this->add_rule(__FUNCTION__, function($data, $args=null) {
			return filter_var($data, FILTER_VALIDATE_IP);
		}, null);
		return $this;
	}
	
	/**
	 * 验证一个字符串是Email地址
	 * @return \classlib\validator\auditor
	 */
	public function email() {
		$this->add_rule(__FUNCTION__, function($data, $args=null) {
			return filter_var($data, FILTER_VALIDATE_EMAIL);
		}, null);
		return $this;
	}
	
	/**
	 * 验证是否是手机号码或者电话号码
	 * @return \classlib\validator\auditor
	 */
	public function mobile() {
		$this->add_rule(__FUNCTION__, function($data, $args=null) {
			return preg_match('/^[+]?[\d]{7,13}$/', $data);
		}, null);
		return $this;
	}
	
	/**
	 * 验证一个字符串是否匹配正则
	 * @return \classlib\validator\auditor
	 */
	public function match($pattern) {
		$this->add_rule(__FUNCTION__, function($data, $args) {
			return preg_match($args, $data);
		}, $pattern);
		return $this;
	}
	
	/**
	 * 验证一个字符串是字母组成
	 * @return \classlib\validator\auditor
	 */
	public function alpha() {
		$this->add_rule(__FUNCTION__, function($data, $args) {
			return preg_match($args, $data);
		}, '/^[a-z]+$/i');
		return $this;
	}
	
	/**
	 * 验证一个字符串是数字|字母组成
	 * @return \classlib\validator\auditor
	 */
	public function alphanum() {
		$this->add_rule(__FUNCTION__, function($data, $args) {
			return preg_match($args, $data);
		}, '/^[0-9a-z]+$/i');
		return $this;
	}
	
	/**
	 * 验证一个字符串是数字组成
	 * @return \classlib\validator\auditor
	 */
	public function numeric() {
		$this->add_rule(__FUNCTION__, function($data, $args=null) {
			return is_numeric($data);
		}, null);
		return $this;
	}
	
	/**
	 * 验证一个字符串至少$min长
	 * @param int $min
	 * @return \classlib\validator\auditor
	 */
	public function minlen($min) {
		$this->add_rule(__FUNCTION__, function($data, $min) {
			return mb_strlen($data, 'utf8') >= $min;
		}, $min);
		return $this;
	}
	
	/**
	 * 验证一个字符串至多$max长
	 * @param int $max
	 * @return \classlib\validator\auditor
	 */
	public function maxlen($max) {
		$this->add_rule(__FUNCTION__, function($data, $max) {
			return mb_strlen($data, 'utf8') <= $max;
		}, $max);
		return $this;
	}
	
	/**
	 * 验证一个字符串长度在 min max之间
	 * @param int $min
	 * @param int $max
	 * @return \classlib\validator\auditor
	 */
	public function lbetween($min, $max) {
		$this->add_rule(__FUNCTION__, function($data, $args) {
			$nlen = mb_strlen($data, 'utf8');
			return ($nlen >= $args[0] && $nlen <= $args[1]);
		}, array($min, $max));
		return $this;
	}
	
	/**
	 * 验证一个字段属于日期字段yyyy:mm:dd
	 * @return \classlib\validator\vdate
	 */
	public function date() {
		$this->add_rule(__FUNCTION__, function($data, $args) {
			$data = str_replace('/', '-', $data);
			if (!preg_match($args, $data)) {
				return false;
			}
			list($year, $mon, $day) = explode('-', $data);
			if (intval($mon) > 12 || intval($day) > 31) {
				return false;
			}
			return true;
		}, self::$pdate);
		return $this;
	}
	
	/**
	 * 验证一个字段属于时间字段hh:mm:ss
	 * @return \classlib\validator\vdate
	 */
	public function time() {
		$this->add_rule(__FUNCTION__, function($data, $args) {
			$data = str_replace(' ', ':', $data);
			if (!preg_match($args, $data)) {
				return false;
			}
			list($hour, $min, $sec) = explode(':', $data);
			if (intval($hour) > 23 || intval($min) > 59 || $sec > 59) {
				return false;
			}
			return true;
		}, self::$ptime);
		return $this;
	}
	
	/**
	 * 验证一个字段属于日期时间yyyy:mm:dd hh:mm:ss
	 * @return \classlib\validator\vdate
	 */
	public function datetime() {
		$this->add_rule(__FUNCTION__, function($data, $args) {
			$datetime = explode(' ', $data);
			if (count($datetime) != 2) {
				return false;
			}
			if (!preg_match($args[0], $datetime[0]) || !preg_match($args[1], $datetime[1])) {
				return false;
			}
			list($year, $mon, $day) = explode('-', $datetime[0]);
			if (intval($mon) > 12 || intval($day) > 31) {
				return false;
			}
			list($hour, $min, $sec) = explode(':', $datetime[1]);
			if (intval($hour) > 23 || intval($min) > 59 || $sec > 59) {
				return false;
			}
			return true;
		}, array(self::$pdate, self::$ptime));
		return $this;
	}
	
	/**
	 * 验证一个字段属于时间戳整型且大于0
	 * @return \classlib\validator\vdate
	 */
	public function timestamp() {
		$this->add_rule(__FUNCTION__, function($data, $args=null) {
			if (is_numeric($data) && $data > 0) {
				return true;
			}
			return false;
		}, null);
		return $this;
	}
	
	/**
	 * 数值比较，在min max之间
	 * @param double $min
	 * @param double $max
	 * @return \classlib\validator\numeric
	 */
	public function between($min, $max) {
		$this->add_rule(__FUNCTION__, function($data, $args) {
			return ($data >= $args[0] && $data <= $args[1]);
		}, array($min, $max));
		return $this;
	}
	
	/**
	 * 数值比较，不能大于$max
	 * @param double $max
	 * @return \classlib\validator\numeric
	 */
	public function max($max) {
		$this->add_rule(__FUNCTION__, function($data, $max) {
			return $data <= $max;
		}, $max);
		return $this;
	}
	
	/**
	 * 数值比较，不能小于$min
	 * @param double $min
	 * @return \classlib\validator\numeric
	 */
	public function min($min) {
		$this->add_rule(__FUNCTION__, function($data, $min) {
			return $data >= $min;
		}, $min);
		return $this;
	}
}

